﻿#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;



//#include "string.h"

//STL简介

//string类

//pong -- ASCII表
//int main()
//{
//	//编码表UTF-8
//	char str[] = "你干嘛";
//	cout << sizeof(str) << endl;
//
//	//汉字编码
//	str[3]++;
//	cout << str << endl;
//
//	str[3]++;
//	cout << str << endl;
//
//	str[3]++;
//	cout << str << endl;
//
//	return 0;
//}


//string 构造函数
//int main()
//{
//	string s1;
//	string s2("hello wold");
//
//	//隐式类型转换
//	string s3 = "hello world";
//
//	//从s3的第六个字符开始取三个字符
//	string s4(s3, 6, 3);
//	cout << s4 << endl;
//
//	//超过了范围就取到末尾
//	string s5(s3, 6, 12);
//	cout << s5 << endl;
//
//	//如果不给第三个参数呢？ 官方文档给了一个缺省值 -- npos -- 42亿多
//	//一个字符串不可能有那么长，所有默认取到结尾
//	string s6(s3, 6);
//	cout << s6 << endl;
//
//	string s7("hello world", 6);
//	cout << s7 << endl;
//
//	string s8(10, 'x');
//	cout << s8 << endl;
//
//	//size_t是一种无符号整数类型就是unsigned int
//	for (size_t i = 0; i < s2.size(); i++)
//	{
//		s2[i]++;
//	}
//	cout << s2 << endl;
//
//	for (size_t i = 0; i < s2.size(); i++)
//	{
//		cout << s2[i] << " ";
//	}
//
//	//析构函数了解即可
//	return 0;
//}


//string的Capacity部分


//int main()
//{
//	string s1("hello world");
//	
//	//字符串有效数据位数
//	//size方法跟length是没有区别的
//	//size是为了跟stl保持一致后面再加入的，建议用size
//	cout << s1.size() << endl;
//	cout << s1.length() << endl;
//
//	//字符串容量
//	cout << s1.capacity() << endl;
//
//	//字符串所能达到的最大长度
//	cout << s1.max_size() << endl;
//
//	return 0;
//}


//string


//class string
//{
//private:
//	char* _ptr;
//	char _buf[16];
//	size_t _size;
//	size_t _capacity;
//};

//string扩容
//int main()
//{
//	//观察扩容的情况,不同对象可能不同
//	//对于库里面的string第一次是2倍扩容，其余次数是1.5倍扩容
//	string s("hello world");
//
//	size_t sz = s.capacity();
//	cout << "capacity: " << sz << '\n';
//	cout << "making s grow:\n";
//
//	//调试观察string内部成员,capacity超过16的话就不会存在buf数组里面了，而是存在于ptr申请的堆空间上了
//	for (int i = 0; i < 100; ++i)
//	{
//		s.push_back('c');
//		if (sz != s.capacity())
//		{
//			sz = s.capacity();
//			cout << "capacity changed: " << sz << '\n';
//		}
//	} 
//	return 0;
//}

//int main()
//{
//	string s1("hello world");
//
//	//扩容但不初始化 111
//	s1.reserve(100);
//	cout << s1.size() << endl;//11
//	cout << s1.capacity() << endl;//111
//
//	string s2("hello world");
//
//	//扩容初始化,未给第二个参数的话初始化成缺省值0
//	s2.resize(100);
//	cout << s2.size() << endl;//100
//	cout << s2.capacity() << endl;//111
//
//	//扩容初始化，将一百个位置全部初始化为x
//	s2.resize(100, 'x');
//	cout << s2.size() << endl;
//	cout << s2.capacity() << endl;
//
//	//如果比size小，还可以删除数据，保留前五个数据不变,但容量不会缩容
//	s2.resize(5);
//	cout << s2.size() << endl;//5
//	cout << s2.capacity() << endl;//111
//
//	return 0;
//}


//string访问操作
//int main()
//{
//	string s("hello world");
//
//	cout << s[0] << endl;
//	cout << s.at(0) << endl;
//
//	//操作符越界：内部是直接assert断言的
//	//s[100];
//
//	//at方法越界的话是抛异常，可以被捕获到
//	try
//	{
//		s.at(100);
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//
//	return 0;
//}


////string遍历操作
//void Func(const string& str)
//{
//	//如果继续用正常迭代器编译不通过 - const对象不允许写权限放大
//	//可以使用const迭代器，遍历和读容器的数据,不能写
//
//	//string::const_iterator it = str.begin();
//	auto it = str.begin();
//	while (it != str.end())
//	{
//		cout << *it << " ";
//		it++;
//	}
//	cout << endl;
//
//	//string::const_reverse_iterator rit = str.rbegin();
//	auto rit = str.rbegin();
//	while (rit != str.rend())
//	{
//		cout << *rit << " ";
//		++rit;
//	}
//	cout << endl;
//}
////string内迭代器
//int main()
//{
//	string s("hello world");
//
//	//正向迭代器
//	//string::iterator it = s.begin();
//
//	auto it = s.begin();
//	while (it != s.end())
//	{
//		cout << *it << " ";
//		it++;
//	}
//	cout << endl;
//
//	//反向迭代器
//	//string::reverse_iterator rit = s.rbegin();
//
//	auto rit = s.rbegin();
//	while (rit != s.rend())
//	{
//		cout << *rit << " ";
//		++rit;
//	}
//	cout << endl;
//
//	Func(s);
//
//	return 0;
//}
 

//int main(){
//	string str("hello world");
//
//	for (auto c : str) {
//		cout << c << " ";
//	}
//
//	return 0;
//}
//看起来数组加下标的访问方式在string这里很实用，反而迭代器不好用
//但是这种访问方式仅适用于数组结构，而对于树形结构，哈希表等就不起作用了
//而迭代器是通用的

//c++11提供了cbegin(),cend();//为了区分const对象


//string对象修改操作
//int main(){
//	string s1("hello");
//
//
//	//追加一个字符
//	s1.push_back(' *');
//	cout << s1 << endl;
//
//	//追加一个字符串
//	s1.append("world");
//	cout << s1 << endl;
//
//	s1.clear();
//
//	//通用 -- 推荐使用
//	s1 += "hello ";
//	s1 += 'w';
//	s1 += "orld";
//	cout << s1 << endl;

//	return 0;
//}

//看官方文档
//insert  erase replace
//int main()
//{
//	//insert：插入数据，不推荐经常使用 - 时间复杂度高,效率低
//	string s1("world");
//
//	//任意位置插入字符串
//	s1.insert(0, "hello");
//	cout << s1 << endl;
//
//	//插入多个字符
//	s1.insert(5, 3,  'a');
//	cout << s1 << endl;
//	
//	//迭代器大法
//	s1.insert(s1.begin()        + 5, ' ');
//	cout << s1 << endl;
//	
//	//迭代器插入区间后面我们再讲
//
//	//erase：删除数据，也存在挪动数据,效率低下
//	string s2("hello world");
//
//	//第五个位置开始删除1个字符
//	s2.erase(5, 1);
//	cout << s2 << endl;
//
//	//传入迭代器,删除该位置字符
//	s2.erase(s2.begin() + 5);
//	cout << s2 << endl;
//
//	//超过长度的时候，直接删到字符串尾部,因为给了缺省值npos
//	s2.erase(5, 30);
//	cout << s2 << endl;
//
//	//replace：替换字符，效率也比较低下
//	string s3("hello world");
//
//	s3.replace(5, 2, "%20");
//	cout << s3 << endl;
//
//	//swap
//	s1.swap(s2);
//	cout << s1 << endl;
//	cout << s2 << endl;
//
//	swap(s1, s2);
//	cout << s1 << endl;
//	cout << s2 << endl;
//
//	//有什么区别?
//	//实际上我们直接库里面的swap函数会比用模板类生成的函数高效许多
//
//
//	return 0;
//}


//void Test1()
//{
//	//c_str：将字符串识别成const char*，以\0为准认定为末尾
//	string s1("hello world");
//
//	//区别：流插入按照size()打印，c_str按照\0终止位置进行打印
//	s1 += '\0';
//	s1 += "xxxxx";
//	cout << s1 << endl;
//	cout << s1.c_str() << endl;
//
//	//我们可以用c_str来将string对象转换为const char*
//	string filename("Work.cpp");
//	FILE* fout = fopen(filename.c_str(), "r");
//	if (fout == nullptr)
//	{
//		perror("fopen fail");
//		exit(-1);
//	}
//	cout << "Work.cpp:" << endl;
//	char ch = fgetc(fout);
//	while (ch != EOF)
//	{  
//		cout << ch;
//		ch = fgetc(fout);
//	}
//	fclose(fout);
//
//}
//
//void Test2()
//{
//	string file("string.cpp.tar.zip");
//
//	//从后往前找rfind
//	size_t pos = file.rfind('.');
//	if (pos != string::npos)
//	{
//		//string suffix = file.substr(pos, file.size() - pos);
//		string suffix = file.substr(pos);
//		cout << suffix << endl;
//	}
//
//	// 取出url中的域名
//	string url("http://www.cplusplus.com/reference/string/string/find/");
//	cout << url << endl;
//	size_t start = url.find("://");
//	if (start == string::npos)
//	{
//		cout << "invalid url" << endl;
//		return 0;
//	}
//	start += 3;
//	size_t finish = url.find('/', start);
//	string address = url.substr(start, finish - start);
//	cout << address << endl;
//
//	// 删除url的协议前缀
//	pos = url.find("://");
//	url.erase(0, pos + 3);
//	cout << url << endl;
//}


//void Test3()
//{
//	//find_first_of 顺着找，一旦输入字符串中任意一个字符匹配成功则返回其位置
//	//find_last_of 倒着找,一旦输入字符串中任意一个字符匹配成功则返回其位置
//	string str("Please, replace the vowels in this sentence by asterisks.");
//	size_t found = str.find_first_of("aeiou");
//	while (found != string::npos)
//	{
//		str[found] = '*';
//		found = str.find_first_of("aeiou", found + 1);
//	}
//
//	cout << str << '\n';
//
//	string s1("hello world");
//	string s2("hello world");
//
//	//字符串比较
//	cout << (s1 == s2) << endl;
//	cout << (s1 == "hello world") << endl;
//	cout << ("hello world" == s1) << endl;
//
//}

//getline
//int main() {
//	string s1;
//
//	//因为有流插入和流提取运算符重载，所以可以直接打印string
//	//输入hello world
//	//cin >> s1;
//	////打印hello 
//	//cout << s1 << endl;
//
//	//这是为什么呢？
//	//这是因为流插入符会识别空格跟换行符作为输入结束的标志
//	//怎么解决呢？getline可以输入空格，并以\n作为结束标志
//
//	string s2;
//
//	
//	getline(cin, s2);
//	cout << s2 << endl;//hello world
//
//	return 0;
//}

//oj题

//字符串最后一个单词的长度
//int main()
//{
//	string str;
//	//默认遇到空格或者换行就是多个值之间分隔符,所以输入的串一部分还在缓冲区
//	//cin >> str;
//
//	//此处应该用getline来解决此类问题
//	getline(cin, str);
//
//	size_t pos = str.rfind(' ');
//	if (pos != string::npos)
//	{
//		cout << str.size() - pos - 1 << endl;
//	}
//	else
//	{
//		cout << str.size() << endl;
//	}
//
//	return 0;
//}

//字符串相加 **
//string addStrings(string num1, string num2)
//{
//	int i = num1.size() - 1, j = num2.size() - 1, ret = 0;
//
//	string str;
//	//避免扩容
//	str.reserve(num1.size() > num2.size() ? num1.size() + 1 : num2.size() + 1);
//	while (i >= 0 || j >= 0 || ret != 0)
//	{
//		if (i >= 0) ret += num1[i--] - '0';
//		if (j >= 0) ret += num2[j--] - '0';
//		str += (ret % 10 + '0');
//		ret /= 10;
//	}
//	reverse(str.begin(), str.end());
//
//	return str;
//}


//int main()
//{
//	try {
//		ljk::test_string10();
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//
//	return 0;
//}

//int main()
//{
//	ljk::string s1;
//	std::string s2;
//
//	cout << sizeof(s1) << endl;//24
//	cout << sizeof(s2) << endl;//40
//
//	ljk::string s3("111111");
//	std::string s4("1111111");
//
//
//	//pong. g++下string的内存只有四个字节
//	//引用计数的浅拷贝
//	cout << sizeof(s3) << endl;//24
//	cout << sizeof(s4) << endl;//40
//
//
//	return 0;
//}

//上课oj题

//反转字母
//bool isLetter(char c)
//{
//	if (c >= 'a' && c <= 'x' || c >= 'A' && c <= 'Z')
//	{
//		return true;
//	}
//	else
//	{
//		return false;
//	}
//}
//string reverseOnlyLetters(string s) 
//{
//	int begin = 0, end = s.size() - 1;
//
//	while (begin < end)
//	{
//		while (begin < end && !isLetter(s[begin]))
//		{
//			begin++;
//		}
//		while (end > begin && !isLetter(s[end]))
//		{
//			end--;
//		}
//		swap(s[begin], s[end]);
//		begin++;
//		end--;
//	}
//	return s;
//}
//统计第一个只出现一次的字符
//int firstUniqChar(string s) {
//	int array[26] = { 0 };
//	for (int i = 0; i < s.size(); i++) {
//		array[s[i] - 97]++;
//	}
//
//
//	for (int i = 0; i < s.size(); i++) {
//		if (array[s[i] - 97] == 1) {
//			return i;
//		}
//	}
//	return -1;
//}


//L:JZ05.替换空格
//int main()
//{
//
//	//简单，但不高效
//	string s1("hello world i love you");
//	size_t num = 0;
//	for (auto ch : s1)
//	{
//		if (ch == ' ')
//		{
//			num++;
//		}
//	}
//
//	//提前开空间，避免replace时扩容
//	s1.reserve(s1.size() + 2 * num);
//
//	//替换空格oj题
//	size_t pos = s1.find(' ');
//	while (pos != string::npos)
//	{
//		s1.replace(pos, 1, "%20");
//		pos = s1.find(' ', pos + 3);
//	}
//	cout << s1 << endl;
//
//	return 0;
//}

//int main()
//{
//	//既高效又简单
//	string s1("hello world i love you");
//	string newStr;
//	size_t num = 0;
//	for (auto ch : s1)
//	{
//		if (ch == ' ')
//		{
//			num++;
//		}
//	}
//
//	//提前开空间，避免replace时扩容
//	newStr.reserve(s1.size() + 2 * num);
//	for (auto ch : s1)
//	{
//		if (ch != ' ')
//		{
//			newStr += ch;
//		}
//		else
//		{
//			newStr += "%20";
//		}
//	}
//	s1 = newStr;
//	cout << s1 << endl;
//
//	return 0;
//}